﻿using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Globalization;
using System.IO;
using System.Net;
using System.Reflection;
using System.Security.Permissions;
using System.Text;
using System.Web.Services.Description;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.CSharp;

namespace ServiceConsumer
{
    public class WSProxy
    {
        [SecurityPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]
        public static object CallWebService(string webServiceAsmxUrl, string serviceName, string methodName, object[] args)
        {
            //System.Net.WebClient client = new System.Net.WebClient();

            //// Connect To the web service
            //System.IO.Stream stream = client.OpenRead(webServiceAsmxUrl + "?wsdl");

            //// Now read the WSDL file describing a service.
            //ServiceDescription description = ServiceDescription.Read(stream);

            XmlTextReader xmlreader = new XmlTextReader(webServiceAsmxUrl + "?wsdl");
            ServiceDescription description = ServiceDescription.Read(xmlreader);

            ///// LOAD THE DOM /////////

            // Initialize a service description importer.
            ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
            importer.ProtocolName = "Soap12"; // Use SOAP 1.2.
            importer.AddServiceDescription(description, null, null);

            // Generate a proxy client.                      
            importer.Style = ServiceDescriptionImportStyle.Client;

            // Generate properties to represent primitive values.
            importer.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;

            // Initialize a Code-DOM tree into which we will import the service.
            CodeNamespace nmspace = new CodeNamespace();
            CodeCompileUnit unit1 = new CodeCompileUnit();
            unit1.Namespaces.Add(nmspace);

            // Import the service into the Code-DOM tree. This creates proxy code that uses the service.
            ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1);

            if (warning == 0) // If zero then we are good to go
            {
                // Generate the proxy code
                CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");

                // Compile the assembly proxy with the appropriate references
                string[] assemblyReferences = new string[5] { "System.dll", "System.Web.Services.dll", "System.Web.dll", "System.Xml.dll", "System.Data.dll" };
                CompilerParameters parms = new CompilerParameters(assemblyReferences);
                parms.GenerateInMemory = true;
                CompilerResults results = provider1.CompileAssemblyFromDom(parms, unit1);

                // Check For Errors
                if (results.Errors.Count > 0)
                {
                    foreach (CompilerError oops in results.Errors)
                    {
                        System.Diagnostics.Debug.WriteLine("=Compiler error=====");
                        System.Diagnostics.Debug.WriteLine(oops.ErrorText);
                    }

                    throw new Exception("Compile Error Occured calling webservice. Check Debug ouput window.");
                }

                // Finally, Invoke the web service method
                object wsvcClass = results.CompiledAssembly.CreateInstance(serviceName);
                MethodInfo mi = wsvcClass.GetType().GetMethod(methodName);
                return mi.Invoke(wsvcClass, args);
            }

            return null;
        }
    
        [SecurityPermissionAttribute(SecurityAction.Demand, Unrestricted = true)]
        public static object CallWebService(string webServiceAsmxUrl, string methodName, object[] args)
        {
            try
            {
                Uri uri = new Uri(webServiceAsmxUrl + "?wsdl");
                
                Type service;

                WebRequest webRequest = WebRequest.Create(uri);
                Stream requestStream = webRequest.GetResponse().GetResponseStream();

                // Get a WSDL file describing a service
                ServiceDescription sd = ServiceDescription.Read(requestStream);

                //Get Service Name QLHSService
                string sdName = sd.Services[0].Name;

                // Initialize a service description servImport
                ServiceDescriptionImporter servImport = new ServiceDescriptionImporter();
                servImport.AddServiceDescription(sd, String.Empty, String.Empty);
                servImport.ProtocolName = "Soap";
                servImport.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties;

                CodeNamespace nameSpace = new CodeNamespace();
                CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
                codeCompileUnit.Namespaces.Add(nameSpace);

                // Set Warnings
                ServiceDescriptionImportWarnings warnings = servImport.Import(nameSpace, codeCompileUnit);

                if (warnings == 0)
                {
                    StringWriter stringWriter = new StringWriter(CultureInfo.CurrentCulture);
                    CSharpCodeProvider prov = new CSharpCodeProvider();
                    prov.GenerateCodeFromNamespace(nameSpace, stringWriter, new CodeGeneratorOptions());

                    // Compile the assembly with the appropriate references
                    string[] assemblyReferences;
                    assemblyReferences = new string[] { "System.Web.Services.dll", "System.Xml.dll", "System.Data.dll" };

                    CompilerParameters param = new CompilerParameters(assemblyReferences);
                    param.GenerateExecutable = false;
                    param.GenerateInMemory = true;
                    param.TreatWarningsAsErrors = false;
                    param.WarningLevel = 4;

                    CompilerResults results = new CompilerResults(new TempFileCollection());
                    results = prov.CompileAssemblyFromDom(param, codeCompileUnit);
                    Assembly assembly = results.CompiledAssembly;
                    service = assembly.GetType(sdName);
                    
                    MethodInfo method = service.GetMethod(methodName);

                    Object obj = Activator.CreateInstance(service);

                    Object response = method.Invoke(obj, args);

                    return response;
                }
                else
                {
                    throw new Exception("Error: " + warnings.ToString());
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static T ConvertType<T>(object input)
        {

            XmlSerializer serializer = new XmlSerializer(input.GetType());
            XmlSerializer deserializer = new XmlSerializer(typeof(T));

            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                serializer.Serialize(sw, input);
            }

            using (StringReader sr = new StringReader(sb.ToString()))
            {
                return (T)deserializer.Deserialize(sr);
            }
        }
    }
}